package org.softee.functional;

import java.util.ArrayList;
import java.util.Collection;

import org.softee.functional.functions.Mapper;
import org.softee.functional.functions.Predicate;
import org.softee.functional.functions.ReduceFunction;
import org.softee.functional.functions.Transposal;
import org.softee.functional.helper.Preconditions;

public abstract class AbstractFunctional<F> implements Functional<F> {
    protected final Collection<F> data;

    AbstractFunctional(Collection<F> data) {
        Preconditions.notNull(data);
        this.data = data;
    }

    @Override
    public Collection<F> values() {
        return data;
    }

    @Override
    public <T extends Collection<? super F>> T into(T target) {
        target.addAll(data);
        return target;
    }

    protected F doReduce(ReduceFunction<F> reduceFunction, Collection<F> data) {
        return reduceFunction.apply(data);
    }

    protected Collection<F> doFilter(Predicate<? super F> predicate, Collection<F> data) {
        Collection<F> results = new ArrayList<F>(data.size());
        for (F input : data) {
            if (predicate.apply(input)) {
                results.add(input);
            }
        }
        return results;
    }

    protected <T> Collection<T> doMap(Mapper<? super F, ? extends T> function, Collection<F> data) {
        Collection<T> results = new ArrayList<T>(data.size());
        for (F input: data) {
            T result = function.apply(input);
            results.add(result);
        }
        return results;
    }

    protected Collection<F> doTranspose(Transposal<F> transposal, Collection<F> data) {
        return transposal.apply(data);
    }
}
